package com.buyman.server.bo.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import com.buyman.server.bean.gp.ExcepcionHorario;
import com.buyman.server.bean.gp.FranjaHoraria;
import com.buyman.server.bean.gp.Imagen;
import com.buyman.server.bean.gp.Proveedor;
import com.buyman.server.bean.gp.Publicidad;
import com.buyman.server.bean.gp.Punto;
import com.buyman.server.bean.gp.RedSocial;
import com.buyman.server.bean.gp.Rubro;
import com.buyman.server.bean.gp.ServicioProveedor;
import com.buyman.server.bean.gp.TipoSucesoProveedor;
import com.buyman.server.bean.pp.VistaProductos;
import com.buyman.server.bean.us.Usuario;
import com.buyman.server.bean.us.UsuarioProveedorEstado;
import com.buyman.server.bo.IProveedorBO;
import com.buyman.server.dao.IGenericDAO;

public class ProveedorBOImpl implements IProveedorBO{
	
	private IGenericDAO genericDAO;
	
	public List<Publicidad> getPublicidadesByProveedor (String idProveedor)
	{
		String HQL = "SELECT publicidades FROM " + Proveedor.class.getName() + " AS prov WHERE prov.id=" + idProveedor;
		return (List<Publicidad>) this.getGenericDAO().findAllByHQL(HQL, false);
	}
	
	public List<Publicidad> getPublicidadesByProveedorOrderByTitulo (String idProveedor)
	{
		String HQL = "FROM " + Publicidad.class.getName() + " WHERE proveedor = " + idProveedor + " ORDER BY titulo";
		return (List<Publicidad>) this.getGenericDAO().findAllByHQL(HQL, false);
	}
	
	public List<Publicidad> getPublicidadesActivasAleatoriaByProveedor (String idProveedor)
	{
		String HQL = "FROM " + Publicidad.class.getName() + " WHERE proveedor = " + idProveedor + " AND activa = 1";
		List<Publicidad> publicidades = this.getGenericDAO().findAllByHQL(HQL, false);
		List<Publicidad> rta = new ArrayList<Publicidad>();
		Random rand = new Random();
		int i = 0;
		List<String> nums = new ArrayList<String>();
		while (i<publicidades.size() && i<3)
		{
			int x = rand.nextInt(publicidades.size());
			String sx = "" + x;
			if (!nums.contains(sx))
			{
				rta.add(publicidades.get(x));
				nums.add(sx);
				i++;
			}
		}
		return rta ;
	}
	
	public List<Publicidad> getPublicidadesActivasAleatoriaBuyman ()
	{
		String HQL = "FROM " + Publicidad.class.getName() + " WHERE proveedor IS NULL AND activa = 1";
		List<Publicidad> publicidades = this.getGenericDAO().findAllByHQL(HQL, false);
		List<Publicidad> rta = new ArrayList<Publicidad>();
		Random rand = new Random();
		int i = 0;
		List<String> nums = new ArrayList<String>();
		while (i<publicidades.size() && i<3)
		{
			int x = rand.nextInt(publicidades.size());
			String sx = "" + x;
			if (!nums.contains(sx))
			{
				rta.add(publicidades.get(x));
				nums.add(sx);
				i++;
			}
		}
		return rta ;
	}
	
	public List<Proveedor> getProveedores ()
	{
		String HQL = "FROM " + Proveedor.class.getName();
		return (List<Proveedor>) this.getGenericDAO().findAllByHQL(HQL, false);
	}
	
	public Proveedor getProveedorById (String idProveedor)
	{
		String HQL = "FROM " + Proveedor.class.getName() + " WHERE id = " + idProveedor;
		return (Proveedor) this.getGenericDAO().findOneByHQL(HQL);
	}
	
	public VistaProductos getVistaProductosByProveedor (String idProveedor)
	{
		String HQL = "FROM " + VistaProductos.class.getName() + " WHERE proveedor = " + idProveedor;
		return (VistaProductos) this.getGenericDAO().findOneByHQL(HQL);
	}
	
	public Proveedor getProveedorByIdentificador (String identificador)
	{
		String HQL = "FROM " + Proveedor.class.getName() + " WHERE identificador = '" + identificador + "'";
		return (Proveedor) this.getGenericDAO().findOneByHQL(HQL);
	}	
	
	public List<Proveedor> getProveedoresTopNOrderByPeso (Integer n)
	{
		String HQL = "FROM " + Proveedor.class.getName() + " ORDER BY peso desc";
		return (List<Proveedor>) this.getGenericDAO().findAllMaxByHQL(HQL, n, 0);
	}
	
	public List<Proveedor> getProveedoresTopNByUbicacionOrderByPeso (Integer n, String idUbicacion)
	{
		String HQL = "FROM " + Proveedor.class.getName() + " WHERE ubicacion=" + idUbicacion + " ORDER BY peso desc";
		return (List<Proveedor>) this.getGenericDAO().findAllMaxByHQL(HQL, n, 0);
	}
	
	public List<Proveedor> getProveedoresLikeNombreOrderByPesoYNombre (String nombre, Integer max, Integer desde)
	{
		String HQL = "FROM " + Proveedor.class.getName() + " WHERE razonSocial LIKE '" + nombre + "%' ORDER BY peso desc, razonSocial asc";
		return (List<Proveedor>) this.getGenericDAO().findAllMaxByHQL(HQL, max, desde);
	}
	
	public List<Proveedor> getProveedoresLikeNombreByTagsOrderByPesoYNombre(String nombre, String idsTag, Integer max, Integer desde)
	{
		StringBuffer HQL = new StringBuffer()
							.append( "FROM " )
							.append( Proveedor.class.getName() )
							.append( " Prov WHERE Prov.razonSocial LIKE '" )
							.append( nombre )
							.append( "%' " )
							.append( "AND EXISTS( from " )
							.append( Proveedor.class.getName() )
							.append( " ProvTemp where ProvTemp.rubros.id IN (" )
							.append( idsTag )
							.append( ") AND ProvTemp.id = Prov.id ) ")
							.append( "ORDER BY Prov.peso desc, Prov.razonSocial asc " );
		return (List<Proveedor>) this.getGenericDAO().findAllMaxByHQL(HQL.toString(), max, desde);
	}
	
	public List<Proveedor> getProveedoresLikeNombreByUbicacionOrderByPesoYNombre (String nombre, String idUbicacion, Integer max, Integer desde)
	{
		String HQL = "FROM " + Proveedor.class.getName() + " WHERE razonSocial LIKE '" + nombre + "%' AND ubicacion=" + idUbicacion + " ORDER BY peso desc, razonSocial asc";
		return (List<Proveedor>) this.getGenericDAO().findAllMaxByHQL(HQL, max, desde);
	}

	public List<Proveedor> getProveedoresLikeNombreByTagsYUbicacionOrderByPesoYNombre(String nombre, String idsTag, String idUbicacion, Integer max, Integer desde)
	{
		StringBuffer HQL = new StringBuffer()
							.append( "FROM " )
							.append( Proveedor.class.getName() )
							.append( " Prov WHERE Prov.razonSocial LIKE '" )
							.append( nombre )
							.append( "%' AND Prov.ubicacion = " )
							.append( idUbicacion )
							.append( " " )
							.append( "AND EXISTS( from " )
							.append( Proveedor.class.getName() )
							.append( " ProvTemp where ProvTemp.rubros.id IN (" )
							.append( idsTag )
							.append( ") AND ProvTemp.id = Prov.id ) ")
							.append( "ORDER BY Prov.peso desc, Prov.razonSocial asc " );
		return (List<Proveedor>) this.getGenericDAO().findAllMaxByHQL(HQL.toString(), max, desde);
	}
	
	public List<Proveedor> getProveedoresLikeNombreByUbicacionLatLongYRadioOrderByPesoYNombre (String nombre, String idUbicacion, Double latitud, Double longitud, Integer radio, Integer max, Integer desde)
	{
		final Double RADIO_TIERRA = 6378.0; // KMs
		final Integer BASE_DIVISION = 950; // Base por la que se divide el radio

		StringBuffer HQL = new StringBuffer()
							.append( "FROM " )
							.append( Proveedor.class.getName() )
							.append( " Prov WHERE Prov.razonSocial LIKE '" )
							.append( nombre )
							.append( "%' " )
		// SUBSELECT PUNTOS
							.append( "AND Prov.vistaConsumidor.tabs.id IN ( SELECT Pu.tabGenerico.id FROM " )
							.append( Punto.class.getName() )
							.append( " Pu WHERE " );
		if( idUbicacion != null )
		{
			HQL.append( "Pu.ubicacion = " )
				.append( idUbicacion )
				.append( " AND ");
		}
		HQL.append( "Pu.tabGenerico.tipo = 4 ")
			.append( "AND ((acos(sin(radians(Pu.latitud)) * sin(radians(" )
			.append( latitud )
			.append( ")) + cos(radians(Pu.latitud)) * cos(radians(" )
			.append( latitud )
			.append( ")) * cos(radians(Pu.longitud) - radians(" )
			.append( longitud )
			.append( "))) * " )
			.append( RADIO_TIERRA )
			.append( ") < " )
			.append( Double.valueOf(radio)/BASE_DIVISION )
			.append( ") ) " )
		// FIN SUBSELECT PUNTOS
			.append( "ORDER BY Prov.peso desc, Prov.razonSocial asc" );

		return (List<Proveedor>) this.getGenericDAO().findAllMaxByHQL(HQL.toString(), max, desde);
	}

	public List<Proveedor> getProveedoresLikeNombreByTagsUbicacionLatLongYRadioOrderByPesoYNombre (String nombre, String idsTag, String idUbicacion, Double latitud, Double longitud, Integer radio, Integer max, Integer desde)
	{
		final Double RADIO_TIERRA = 6378.0; // KMs
		final Integer BASE_DIVISION = 950; // Base por la que se divide el radio

		StringBuffer HQL = new StringBuffer()
							.append( "FROM " )
							.append( Proveedor.class.getName() )
							.append( " Prov WHERE Prov.razonSocial LIKE '" )
							.append( nombre )
							.append( "%' " )
							.append( "AND EXISTS( from " )
							.append( Proveedor.class.getName() )
							.append( " ProvTemp where ProvTemp.rubros.id IN (" )
							.append( idsTag )
							.append( ") AND ProvTemp.id = Prov.id ) ")
		// SUBSELECT PUNTOS
							.append( "AND Prov.vistaConsumidor.tabs.id IN ( SELECT Pu.tabGenerico.id FROM " )
							.append( Punto.class.getName() )
							.append( " Pu WHERE " );
		if( idUbicacion != null )
		{
			HQL.append( "Pu.ubicacion = " )
				.append( idUbicacion )
				.append( " AND ");
		}
		HQL.append( "Pu.tabGenerico.tipo = 4 ")
			.append( "AND ((acos(sin(radians(Pu.latitud)) * sin(radians(" )
			.append( latitud )
			.append( ")) + cos(radians(Pu.latitud)) * cos(radians(" )
			.append( latitud )
			.append( ")) * cos(radians(Pu.longitud) - radians(" )
			.append( longitud )
			.append( "))) * " )
			.append( RADIO_TIERRA )
			.append( ") < " )
			.append( Double.valueOf(radio)/BASE_DIVISION )
			.append( ") ) " )
		// FIN SUBSELECT PUNTOS
			.append( "ORDER BY Prov.peso desc, Prov.razonSocial asc" );

		return (List<Proveedor>) this.getGenericDAO().findAllMaxByHQL(HQL.toString(), max, desde);
	}

	public List<Proveedor> getProveedoresLikeNombreByUbicacionYZonaOrderByPesoYNombre(String nombre, String idUbicacion, Double latitud, Double longitud, Integer max, Integer desde)
	{
		StringBuffer HQL = new StringBuffer()
							.append( "FROM " )
							.append( Proveedor.class.getName() )
							.append( " Prov WHERE Prov.razonSocial LIKE '" )
							.append( nombre )
							.append( "%' " )
							.append( "AND ( " );
		if( idUbicacion != null )
		{
			HQL.append( "( Prov.ubicacion = "+ idUbicacion +" AND Prov.deliveryAUbicacion = true ) OR " );
		}
		// SUBSELECT PUNTOS
		HQL.append( "EXISTS ( SELECT Pu.tabGenerico.id FROM " )
							.append( Punto.class.getName() )
							.append( " Pu WHERE Pu.tabGenerico.vistaConsumidor = Prov.vistaConsumidor AND " );
		if( idUbicacion != null )
		{
			HQL.append( "Pu.ubicacion = " )
				.append( idUbicacion )
				.append( " AND ");
		}
		HQL.append( "Pu.tabGenerico.tipo = 4 ")
			.append( "AND size(Pu.zona) > 0 " )
			.append( "AND puntoDentroZona(" )
			.append( latitud )
			.append( ", " )
			.append( longitud )
			.append( ", minelement(Pu.zona.id)) = 1 ) ) " )
		// FIN SUBSELECT PUNTOS
			.append( "ORDER BY Prov.peso desc, Prov.razonSocial asc" );

		return (List<Proveedor>) this.getGenericDAO().findAllMaxByHQL(HQL.toString(), max, desde);
	}

	public List<Proveedor> getProveedoresLikeNombreByTagsUbicacionYZonaOrderByPesoYNombre(String nombre, String idsTag, String idUbicacion, Double latitud, Double longitud, Integer max, Integer desde)
	{
		StringBuffer HQL = new StringBuffer()
							.append( "FROM " )
							.append( Proveedor.class.getName() )
							.append( " Prov WHERE Prov.razonSocial LIKE '" )
							.append( nombre )
							.append( "%' " )
							.append( "AND EXISTS( from " )
							.append( Proveedor.class.getName() )
							.append( " ProvTemp where ProvTemp.rubros.id IN (" )
							.append( idsTag )
							.append( ") AND ProvTemp.id = Prov.id ) ")
							.append( "AND ( " );
		if( idUbicacion != null )
		{
			HQL.append( "( Prov.ubicacion = "+ idUbicacion +" AND Prov.deliveryAUbicacion = true ) OR " );
		}
		// SUBSELECT PUNTOS
		HQL.append( "EXISTS ( SELECT Pu.tabGenerico.id FROM " )
							.append( Punto.class.getName() )
							.append( " Pu WHERE Pu.tabGenerico.vistaConsumidor = Prov.vistaConsumidor AND " );
		if( idUbicacion != null )
		{
			HQL.append( "Pu.ubicacion = " )
				.append( idUbicacion )
				.append( " AND ");
		}
		HQL.append( "Pu.tabGenerico.tipo = 4 ")
			.append( "AND size(Pu.zona) > 0 " )
			.append( "AND puntoDentroZona(" )
			.append( latitud )
			.append( ", " )
			.append( longitud )
			.append( ", minelement(Pu.zona.id)) = 1 ) ) " )
		// FIN SUBSELECT PUNTOS
			.append( "ORDER BY Prov.peso desc, Prov.razonSocial asc" );

		return (List<Proveedor>) this.getGenericDAO().findAllMaxByHQL(HQL.toString(), max, desde);
	}

	public boolean usuarioEsFavorito (String idProveedor, String idUsuario)
	{
		String HQL = "FROM " + Proveedor.class.getName() + " WHERE id = " + idProveedor + " AND favoritos.id = " + idUsuario;
		if (this.getGenericDAO().findOneByHQL(HQL) != null)
			return true;
		return false;
	}
	
//	public List<Proveedor> getProveedoresFavoritosByUsuarioOrderByPesoUsAndPeso (String idUsuario)
//	{
//		String HQL = "FROM " + Proveedor.class.getName() +  " WHERE favoritos.id = " + idUsuario + " AND usuariosEstados.usuario IS NOT NULL AND peso != 0 ORDER BY usuariosEstados.peso desc, peso desc, razonSocial asc";
//		return (List<Proveedor>) this.getGenericDAO().findAllByHQL(HQL, false);
//	}
	
	public List<UsuarioProveedorEstado> getProveedoresFavoritosByUsuarioOrderByPesoUsAndPeso (String idUsuario)
	{
		String HQL = "FROM " + UsuarioProveedorEstado.class.getName() +  " WHERE proveedor.favoritos.id = " + idUsuario + " AND usuario.id = " + idUsuario + " ORDER BY peso desc, proveedor.peso desc, proveedor.razonSocial asc";
		return (List<UsuarioProveedorEstado>) this.getGenericDAO().findAllByHQL(HQL, false);
	}
	
	public List<FranjaHoraria> getFranjasHorariasComercioByProveedorOrderByHora (String idProveedor)
	{
		String HQL = "FROM " + FranjaHoraria.class.getName() +  " WHERE proveedor = " + idProveedor + " AND tipo = '1' ORDER BY inicio";
		return (List<FranjaHoraria>) this.getGenericDAO().findAllByHQL(HQL, false);
	}
	
	public List<FranjaHoraria> getFranjasHorariasComercioByProveedorByDay (String idProveedor, String dia)
	{
		String HQL = "FROM " + FranjaHoraria.class.getName() +  " WHERE proveedor = " + idProveedor + " AND tipo = '1' AND (todosLosDias = 1 OR " + dia + " = 1) ORDER BY inicio";
		return (List<FranjaHoraria>) this.getGenericDAO().findAllByHQL(HQL, false);
	}
	
	public List<FranjaHoraria> getFranjasHorariasDeliveryByProveedorOrderByHora (String idProveedor)
	{
		String HQL = "FROM " + FranjaHoraria.class.getName() +  " WHERE proveedor = " + idProveedor + " AND tipo = '2' ORDER BY inicio";
		return (List<FranjaHoraria>) this.getGenericDAO().findAllByHQL(HQL, false);
	}
	
	public List<ExcepcionHorario> getExcepcionesHorarioByProveedorOrderByFecha (String idProveedor)
	{
		String HQL = "FROM " + ExcepcionHorario.class.getName() +  " WHERE proveedor = " + idProveedor + " ORDER BY fecha";
		return (List<ExcepcionHorario>) this.getGenericDAO().findAllByHQL(HQL, false);
	}
	
	public List<ExcepcionHorario> getExcepcionesHorarioByFecha (String idProveedor, String fecha)
	{
		String HQL = "FROM " + ExcepcionHorario.class.getName() +  " WHERE proveedor = " + idProveedor + " AND fecha = '" + fecha + "' ORDER BY inicio";
		return (List<ExcepcionHorario>) this.getGenericDAO().findAllByHQL(HQL, false);
	}
	
	public List<ExcepcionHorario> getExcepcionesHorarioActuales (String idProveedor, String fecha)
	{
		String HQL = "FROM " + ExcepcionHorario.class.getName() +  " WHERE proveedor = " + idProveedor + " AND fecha >= '" + fecha + "' ORDER BY fecha asc, inicio";
		return (List<ExcepcionHorario>) this.getGenericDAO().findAllByHQL(HQL, false);
	}
	
	public List<Rubro> getRubrosByTipo (String tipo)
	{
		String HQL = "FROM " + Rubro.class.getName() + " WHERE tipo = '" + tipo + "'";
		return (List<Rubro>) this.getGenericDAO().findAllByHQL(HQL, false);
	}
	
	public Rubro getRubroById (String idRubro)
	{
		String HQL = "FROM " + Rubro.class.getName() + " WHERE id = " + idRubro;
		return (Rubro) this.getGenericDAO().findOneByHQL(HQL);
	}
	
	public List<Rubro> getRubrosLikeNombreOrderByNombre(String nombre, int max, int desde)
	{
		StringBuffer HQL = new StringBuffer()
			.append( " FROM " ).append( Rubro.class.getName() )
			.append( " WHERE nombre LIKE '" ).append( nombre ).append( "%'" )
			.append( " ORDER BY nombre" );
		return (List<Rubro>) this.getGenericDAO().findAllMaxByHQL(HQL.toString(), max, desde);
	}
	
	public List<Rubro> getRubrosOrderByTipo()
	{
		String HQL = "FROM " + Rubro.class.getName() + " ORDER BY tipo";
		return (List<Rubro>) this.getGenericDAO().findAllByHQL(HQL, false);
	}
	
	public TipoSucesoProveedor getSucesoProveedorBySuceso (List<TipoSucesoProveedor> sucesosProveedor, String suceso)
	{
		Iterator<TipoSucesoProveedor> itSucesos = sucesosProveedor.iterator();
		while (itSucesos.hasNext())
		{
			TipoSucesoProveedor sucesoProveedor = itSucesos.next();
			if (sucesoProveedor.getTipoSuceso().getNombre().equals(suceso))
				return sucesoProveedor;
		}
		return null;
	}
	
	public void guardarProveedor (Proveedor proveedor)
	{
		this.getGenericDAO().persist(proveedor);
	}
	
	public void guardarPublicidad (Publicidad publicidad)
	{
		this.getGenericDAO().persist(publicidad);
	}
	
	public void guardarImagen (Imagen imagen)
	{
		this.getGenericDAO().persist(imagen);
	}
	
	public void guardarRedSocial (RedSocial redSocial)
	{
		this.getGenericDAO().persist(redSocial);
	}
	
	public void guardarServicioProveedor (ServicioProveedor servicioProveedor)
	{
		this.getGenericDAO().persist(servicioProveedor);
	}
	
	public void guardarVistaProductos (VistaProductos vistaProductos)
	{
		this.getGenericDAO().persist(vistaProductos);
	}
	
	public void guardarFranjaHoraria (FranjaHoraria franjaHoraria)
	{
		this.getGenericDAO().persist(franjaHoraria);
	}
	
	public void guardarExcepcionHorario (ExcepcionHorario excepcionHorario)
	{
		this.getGenericDAO().persist(excepcionHorario);
	}
	
	public void guardarTipoSucesoProveedor (TipoSucesoProveedor tipoSucesoProveedor)
	{
		this.getGenericDAO().persist(tipoSucesoProveedor);
	}
	
	public void eliminarPublicidad (Publicidad publicidad)
	{
		this.getGenericDAO().delete(publicidad);
	}
	
	public void eliminarImagen (Imagen imagen)
	{
		this.getGenericDAO().delete(imagen);
	}
	
	public void eliminarRedSocial (RedSocial redSocial)
	{
		this.getGenericDAO().delete(redSocial);
	}
	
	public void eliminarServicioProveedor (ServicioProveedor servicioProveedor)
	{
		this.getGenericDAO().delete(servicioProveedor);
	}
	
	public void eliminarFranjaHoraria (FranjaHoraria franjaHoraria)
	{
		this.getGenericDAO().delete(franjaHoraria);
	}
	
	public void eliminarExcepcionHorario (ExcepcionHorario excepcionHorario)
	{
		this.getGenericDAO().delete(excepcionHorario);
	}
	
	public void eliminarTipoSucesoProveedor (TipoSucesoProveedor tipoSucesoProveedor)
	{
		this.getGenericDAO().delete(tipoSucesoProveedor);
	}
	
	public void refrescarProveedor (Proveedor proveedor)
	{
		this.getGenericDAO().refresh(proveedor);
	}
	
	public IGenericDAO getGenericDAO() {
		return genericDAO;
	}

	public void setGenericDAO(IGenericDAO genericDAO) {
		this.genericDAO = genericDAO;
	}

}
